package cn.jhz.learn.community_dynamic.app.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import cn.jhz.learn.community_dynamic.common.bean.JsonData;
import cn.jhz.learn.community_dynamic.common.exception.RequestException;
import cn.jhz.learn.community_dynamic.common.util.MineCommonUtil;
import cn.jhz.learn.community_dynamic.dao.CommentJpaRepository;
import cn.jhz.learn.community_dynamic.dao.PostJpaRepository;
import cn.jhz.learn.community_dynamic.dao.UserJpaRepository;
import cn.jhz.learn.community_dynamic.manager.UserManager;
import cn.jhz.learn.community_dynamic.manager.VerificationCodeManager;
import cn.jhz.learn.community_dynamic.model.UserEntity;
import cn.jhz.learn.community_dynamic.qo.TokenBind;
import cn.jhz.learn.community_dynamic.qo.UserInfo;
import cn.jhz.learn.community_dynamic.security.helper.LoginHelper;
import cn.jhz.learn.community_dynamic.security.validation.RegexpRules;
import cn.jhz.learn.community_dynamic.service.CodeService;
import cn.jhz.learn.community_dynamic.service.ImageService;
import cn.jhz.learn.community_dynamic.vo.app.PostUserView;
import cn.jhz.learn.community_dynamic.vo.wbms.ColumnType;
import lombok.Getter;

@RestController
@RequestMapping("api/")
public class UserController {

    private final UserJpaRepository userJpaRepository;
    private final PostJpaRepository postJpaRepository;
    private final CommentJpaRepository commentJpaRepository;
    private final UserManager userManager;
    private final CodeService codeService;
    private final VerificationCodeManager verificationCodeManager;
    private final ImageService imageService;
    private final PasswordEncoder passwordEncoder;

    @Getter
    private class UserView {
	private Long id;
	private String userpic;
	private String username;
	private Byte sex;
	private Byte age;

	private UserView(UserEntity entity) {
	    super();
	    this.id = entity.getLoginId();
	    this.userpic = entity.getUserpic();
	    this.username = entity.getUsername();
	    this.sex = entity.getUserInfo().getSex();
	    this.age = entity.getUserInfo().getAge();
	}

    }

    @Autowired
    public UserController(UserJpaRepository userJpaRepository, PostJpaRepository postJpaRepository,
	    CommentJpaRepository commentJpaRepository, CodeService codeService,
	    VerificationCodeManager verificationCodeManager, ImageService imageService, UserManager userManager,
	    PasswordEncoder passwordEncoder) {
	super();
	this.userJpaRepository = userJpaRepository;
	this.postJpaRepository = postJpaRepository;
	this.commentJpaRepository = commentJpaRepository;
	this.codeService = codeService;
	this.verificationCodeManager = verificationCodeManager;
	this.imageService = imageService;
	this.userManager = userManager;
	this.passwordEncoder = passwordEncoder;
    }

    @GetMapping(value = "user/phone_code", consumes = "application/json")
    public JsonData getPhoneCaptcha(@RequestBody @Validated @Email @NotBlank String phone) {
	this.codeService.sendVerificationCodeByPhone(phone);
	return JsonData.newSuccessInstance("验证码已发送!");
    }

    @GetMapping(value = "user/email_code")
    public JsonData getEmailCaptcha(@RequestParam @Validated @Email @NotBlank String email) {
	this.codeService.sendVerificationCodeByEmail(email);
	return JsonData.newSuccessInstance("验证码已发送!");
    }

    @PatchMapping("auth/edit_userpic")
    @PreAuthorize("hasAuthority('user::patch_per_info_userpic')")
    public JsonData editUserpic(@RequestParam("userpic") MultipartFile userpic) {
	UserEntity entity = (UserEntity) LoginHelper.getLoginUser().get();
	this.userManager.updateInstanceColumn(entity, ColumnType.USERPIC, this.imageService.upload(userpic).getUrl());
	return JsonData.newSuccessInstance((Object) entity.getUserpic());
    }

    @PutMapping("auth/edit_user_info")
    @PreAuthorize("hasAuthority('user::put_per_info')")
    public JsonData editUserInfo(@RequestBody UserInfo userInfo) {
	// TODO 缺少信息校验
	// TODO Manager缺update info
	UserEntity entity = (UserEntity) LoginHelper.getLoginUser().get();
	entity.setUsername(userInfo.getName());
	entity.getUserInfo().setAddress(userInfo.getAddress());
	entity.getUserInfo().setBirthday(userInfo.getBirthday());
	entity.getUserInfo().setJob(userInfo.getJob());
	entity.getUserInfo().setQg(userInfo.getQg());
	entity.getUserInfo().setSex(userInfo.getSex());
	this.userJpaRepository.saveAndFlush(entity);
//	this.userJpaRepository.setFixedUserInfoFor(userInfoEntity, (UserEntity) LoginHelper.getLoginUser().get());
	return JsonData.newSuccessInstance();
    }

    @PatchMapping(value = "auth/repassword", consumes = "application/x-www-form-urlencoded")
    @PreAuthorize("hasAuthority('user::patch_password')")
    public JsonData rePassword(@RequestParam("old_password") String oldPassword,
	    @RequestParam("new_password") String newPassword, @RequestParam("re_new_password") String reNewPassword) {
	// TODO 缺少参数合法性校验
	UserEntity entity = (UserEntity) LoginHelper.getLoginUser().get();
	if (passwordEncoder.matches(oldPassword, entity.getPassword())) {
	    if (newPassword.equals(reNewPassword)) {
		this.userManager.updateInstanceColumn(entity, ColumnType.PASSWORD, passwordEncoder.encode(newPassword));
	    } else {
		throw new RequestException("新密码两次输入不一致!");
	    }
	} else {
	    throw new RequestException("原密码不正确!");
	}

	return JsonData.newSuccessInstance();
    }

    @PatchMapping("auth/user/bind_email")
    @PreAuthorize("hasAuthority('user::bind_email')")
    public JsonData bindEmail(@RequestBody @Validated(value = { RegexpRules.Email.class }) TokenBind emailBind) {
	// TODO 缺少参数合法性
	if (this.verificationCodeManager.getInstance(emailBind.getEmail())
		.orElseThrow(() -> new RequestException("请先获取邮箱验证码!")).equals(emailBind.getCode())) {
	    this.verificationCodeManager.clearInstance(emailBind.getEmail());
	    this.userManager.updateInstanceColumn((UserEntity) LoginHelper.getLoginUser().get(), ColumnType.EMAIL,
		    emailBind.getEmail());
	} else {
	    throw new RequestException("验证码不正确!");
	}
	return JsonData.newSuccessInstance();
    }

    @PatchMapping("auth/user/bind_phone")
    @PreAuthorize("hasAuthority('user::bind_phone')")
    public JsonData bindPhone(@RequestBody @Validated(value = { RegexpRules.Phone.class }) TokenBind phoneBind) {
	UserEntity entity = (UserEntity) LoginHelper.getLoginUser().get();
	if (this.verificationCodeManager.getInstance(phoneBind.getPhone())
		.orElseThrow(() -> new RequestException("请先获取短信验证码!")).equals(phoneBind.getCode())) {
	    this.verificationCodeManager.clearInstance(phoneBind.getPhone());
	    this.userManager.updateInstanceColumn(entity, ColumnType.MOBILE, phoneBind.getPhone());
	} else {
	    throw new RequestException("验证码不正确!");
	}

	return JsonData.newSuccessInstance(entity.getLoginId());
    }

    @GetMapping("search/user")
    public JsonData searchUser(@RequestParam("keyword") String keyword, @RequestParam("page") Integer page) {
	return JsonData.newSuccessInstance(this.userJpaRepository
		.findByStatusAndUsernameContaining((byte) 1, keyword, PageRequest.of(page - 1, 10)).stream()
		.map(UserView::new).collect(Collectors.toList()));
    }

    @GetMapping("user/get_counts/{id}")
    public JsonData getCounts(@PathVariable("id") Long loginId) {
	Map<String, Integer> countMap = new HashMap<>();
	Optional<UserEntity> entityOptional = this.userJpaRepository.findByLoginId(loginId);
	if (entityOptional.isPresent()) {
	    countMap.put("post_count", this.postJpaRepository.countByUserAndStatus(entityOptional.get(), (byte) 1));
	    countMap.put("comments_count", this.commentJpaRepository.countByUserAndStatus(entityOptional.get(), (byte) 1));
	    countMap.put("today_posts_count", this.postJpaRepository.countByUserAndStatusAndCreateTimeAfter(entityOptional.get(),
		    (byte) 1, MineCommonUtil.getToday()));
	    countMap.put("withfollow_count", this.userJpaRepository.countByFolloweds(entityOptional.get()));
	    countMap.put("withfen_count", this.userJpaRepository.countByFollows(entityOptional.get()));
	    countMap.put("total_ding_count", (int) entityOptional.get().getPosts().stream().mapToLong(postEntity -> postEntity.getSupportUsers().stream().count()).sum());
	    countMap.put("friend_count", this.userJpaRepository.countByFollowsAndFollowedsAndIdNot(entityOptional.get(), entityOptional.get(), entityOptional.get().getId()));
	} else {
	    throw new RequestException("用户不存在!");
	}

	return JsonData.newSuccessInstance(countMap);
    }

    @GetMapping("user/get_user_info/{id}")
//    @PreAuthorize("hasAuthority('user::get_per_info')")
    public JsonData getUserInfo(@PathVariable("id") Long id) {
	return JsonData.newSuccessInstance(PostUserView.adpt(this.userJpaRepository.findByLoginId(id).get()));
    }
}
